package it.crosato.stage.server.model.retriever;

import it.crosato.stage.shared.exceptions.DatabaseConnectionException;
import it.crosato.stage.shared.exceptions.NonExistentException;
import it.crosato.stage.shared.exceptions.RetrievingException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.logging.Logger;

public class KGMLRetriever implements IKGMLRetriever {

	/**
	 * Recupera il file KGML gestendo internamente l'interazione con la banca
	 * dati interna e KEGG.
	 * @param pathway codice della via metabolica del file
	 * @param time tempo di scadenza dell'informazione nella banca dati interna
	 * @return il file KGML sotto forma di stringa
	 * @throws RetrievingException se avvengono problemi nel recupero
	 * @throws NonExistentException se la via metabolica in ingresso non esiste
	 */
	@Override
	public String getKGML(String pathway, long time) throws RetrievingException, NonExistentException {

		Logger.getLogger("myLog").info("recupero del file KGML per " + pathway);
		String id = pathway.replace("path:", "");
		try {
			String kgml = searchInDB(pathway, time);
			if (kgml==null) {
				kgml = searchInKEGG(id);
				if (kgml==null) {
					throw new NonExistentException(NonExistentException.KGML);
				}
				storeInDB(pathway, kgml);
			}
			return kgml;
		}
		catch (SQLException sqle) {
			Logger.getLogger("myLog").info("sqle ---> " + sqle.getMessage());
			throw new RetrievingException(RetrievingException.KGML);
		}
		catch (DatabaseConnectionException dbce) {
			Logger.getLogger("myLog").info("dbce ---> " + dbce.getMessage());
			throw new RetrievingException(RetrievingException.KGML);
		}
	}

	/**
	 * Cerca il file KGML nella banca dati interna.
	 * @param id codice della via metabolica del file
	 * @param time tempo di scadenza nella banca dati interna
	 * @return il file in forma di stringa oppure il valore nullo se esso non è presente
	 * nella banca dati o se è troppo vecchio
	 * @throws SQLException se si verificano problemi con le query
	 * @throws DatabaseConnectionException se si verificano problemi con la connessione
	 * alla banca dati
	 */
	private String searchInDB(String id, long time) throws SQLException, 
			DatabaseConnectionException {

		DatabaseConnection.openConnection();
		Statement st = DatabaseConnection.getStatement();
		ResultSet rs = st.executeQuery("SELECT count(*) FROM kgml WHERE id='" + id + "';");
		rs.next();
		if (rs.getInt(1) != 0) {
			Logger.getLogger("myLog").info("file kgml presente nel database");
			rs = st.executeQuery("SELECT * FROM kgml WHERE id='" + id + "';");
			rs.next();
			Long date = rs.getLong("storeDate");
			if (date + time < new Date().getTime()) {
				Logger.getLogger("myLog").info("file kgml troppo vecchio.");
				return null;
			}
			return rs.getString("kgml");
		}
		else {
			Logger.getLogger("myLog").info("file kgml non presente nel database");
			return null;
		}
	}

	/**
	 * Cerca il file in KEGG mediante il collegamento alla pagina del download.
	 * @param id codice della via metabolica del file
	 * @return il file sotto forma di stringa oppure il valore nullo se la via
	 * metabolica non esiste
	 * @throws RetrievingException se si verificano problemi nel recupero
	 */
	private String searchInKEGG(String id) throws RetrievingException {
		BufferedReader Input = null;
		try {
			URL url = new URL("http://www.genome.jp/kegg-bin/download?entry=" + 
					id + "&format=kgml");
			HttpURLConnection httpConn = (HttpURLConnection)url.openConnection();
			httpConn.connect();
			if (httpConn.getResponseCode() == 200) {
				Input = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
				String s = Input.readLine();
				if (s == null || s.equals("")) {
					Logger.getLogger("myLog").info("File KGML non presente in KEGG");
					return null;
				}
				String kgml = s;
				while ((s = Input.readLine()) != null) {
					kgml += s;
				}
				Input.close();
				Logger.getLogger("myLog").info("File KGML recuperato da KEGG");
				return kgml;
			}
			else {
				Logger.getLogger("myLog").info("File KGML non presente in KEGG");
				return null;
			}
		}
		catch (MalformedURLException mue) {
			Logger.getLogger("myLog").info("mue ---> " + mue.getMessage());
			throw new RetrievingException(RetrievingException.KGML);
		}
		catch (IOException ioe) {
			Logger.getLogger("myLog").info("ioe ---> " + ioe.getMessage());
			throw new RetrievingException(RetrievingException.KGML);
		}
		finally {
			try {
				if (Input != null) {
					Input.close();
				}
			} catch (IOException e) { }
		}
	}
	
	/**
	 * Memorizza il file appena recuperato da KEGG nella banca dati interna, eventualmente
	 * sostituendo una versione precedente
	 * @param id codice della via metabolica e dunque del file KGML
	 * @param kgml contenuto del file
	 * @throws DatabaseConnectionException se si verificano problemi di connessione con la
	 * banca dati
	 */
	private void storeInDB(String id, String kgml) throws DatabaseConnectionException {
		Logger.getLogger("myLog").info("inserimento file kgml nel database");
		DatabaseConnection.openConnection();
		Statement st = DatabaseConnection.getStatement();
		try {
			try {
				st.executeQuery("DELETE FROM kgml WHERE id='" + id + "';");
			} catch(SQLException e) { }
			st.executeUpdate("INSERT INTO kgml VALUES('" + id +
					"', '" + kgml + "', '" + new Date().getTime() + "');");
			Logger.getLogger("myLog").info("inserito file kgml nel database");
		}
		catch (SQLException sqle) {
			Logger.getLogger("myLog").info("sqle --> " + sqle.getMessage());
		}
	}
}